home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 726-750 / 750 / fontviewq / fontviewq.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  32KB  |  1,089 lines

  1. /*****************************************************************************\
  2.  * $VER: FontViewQ.c 1.2     DICE/LATTICE C/SAS C/AZTEC C + AmigaOS 2.04/2.1 *
  3.  *                 _                                                         *
  4.  *            _   // (c)1992 by "Quarky" Dieter Temme                        *
  5.  *            \\ //                                                          *
  6.  * :ts=4       \X/ --- Freeware --- ONLY AMIGA MAKES IT POSSIBLE             *
  7.  *                                                                           *
  8.  * commodity to show a character set table on the screen                     *
  9. \*****************************************************************************/
  10.  
  11. #define PRGNAME "FontViewQ"
  12. #define VERSION "1.2"
  13. #define PRGDATE "22.9.92"
  14.  
  15. #define PRGNAMELEN 9 /* to avoid a 'strlen(const)' */
  16.  
  17. #include "amigacompq.h"
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <exec/types.h>
  23. #include <clib/alib_protos.h>
  24. #include <clib/asl_protos.h>
  25. #include <clib/commodities_protos.h>
  26. #include <clib/diskfont_protos.h>
  27. #include <clib/dos_protos.h>
  28. #include <clib/exec_protos.h>
  29. #include <clib/gadtools_protos.h>
  30. #include <clib/graphics_protos.h>
  31. #include <clib/icon_protos.h>
  32. #include <clib/intuition_protos.h>
  33. #include <clib/keymap_protos.h>
  34. #include <clib/locale_protos.h>
  35. #include <clib/utility_protos.h>
  36. #include <devices/keymap.h>
  37. #include <dos/dos.h>
  38. #include <exec/libraries.h>
  39. #include <exec/memory.h>
  40. #include <graphics/text.h>
  41. #include <intuition/gadgetclass.h>
  42. #include <intuition/intuition.h>
  43. #include <libraries/asl.h>
  44. #include <libraries/commodities.h>
  45. #include <libraries/gadtools.h>
  46. #include <libraries/locale.h>
  47.  
  48. #ifdef PRAGMAS_
  49.  #include <pragmas/asl_lib.h>
  50.  #include <pragmas/exec_lib.h>
  51.  #include <pragmas/commodities_lib.h>
  52.  #include <pragmas/diskfont_lib.h>
  53.  #include <pragmas/dos_lib.h>
  54.  #include <pragmas/gadtools_lib.h>
  55.  #include <pragmas/graphics_lib.h>
  56.  #include <pragmas/icon_lib.h>
  57.  #include <pragmas/intuition_lib.h>
  58.  #include <pragmas/keymap_lib.h>
  59.  #include <pragmas/locale_lib.h>
  60.  #include <pragmas/utility_lib.h>
  61. #endif
  62.  
  63. #ifdef LATTICE
  64.  int CXBRK(void) { return 0; }  /* Disable Lattice CTRL-C handling */
  65.  int chkabort(void) { return 0; }
  66. #endif
  67.  
  68. #ifdef AZTEC_C
  69.  void _wb_parse(void) {    extern long Enable_Abort; Enable_Abort= FALSE; }
  70.  void _abort(void) {}
  71. #endif
  72.  
  73. TEXT VersionString[]= "\0$VER: " PRGNAME " " VERSION " (" PRGDATE ")";
  74.  
  75. #define STRINGARRAY
  76. #include "FontViewQ.h"
  77.  
  78. /*>> library bases and locale/catalog variables <<*/
  79. extern struct Library *SysBase;
  80. struct Library *AslBase, *CxBase, *DiskfontBase, *GadToolsBase, *GfxBase,
  81.                 *IconBase, *IntuitionBase, *KeymapBase, *LocaleBase,
  82.                 *UtilityBase;
  83. struct Locale *locale;
  84. struct Catalog *cat;
  85.  
  86. /*>> miscellaneous variables <<*/
  87. struct NewBroker newbroker=        /* newbroker structure */
  88. {    5, PRGNAME, "V" VERSION " (c)1992 by \"Quarky\" Dieter Temme", NULL,
  89.     NBU_UNIQUE|NBU_NOTIFY, COF_SHOW_HIDE
  90. };
  91. CxObj *broker;                    /* Commodities' broker structure */
  92. TEXT *hotkey;                    /* hotkey description */
  93. struct MsgPort *brokport;        /* port for Commodities' messages */
  94. struct FontRequester *freq;        /* ASL's font requester structure */
  95. APTR vi;                        /* Intuition's visual information */
  96. struct Screen *pubscr;            /* pointer to public screen's structure */
  97. struct Window *win;                /* pointer to FontViewQ's window structure */
  98. struct Gadget *congad;            /* pointer to GadTools' anchor gadget struct */
  99. struct RastPort *rp;            /* pointer to screen's rastport */
  100. ULONG winsig;                    /* signal flag of window's userport */
  101. struct TextFont *tabfont;        /* actual font structures for table */
  102. struct TextAttr tabtattr;
  103. UWORD tabxsize;                    /* number of keys in a line of the table */
  104. UWORD tabnumx;                    /* number of rows on the table page */
  105. UWORD tabnumy;                    /* number of lines on the table page */
  106. UWORD tablen;                    /* number of keys on one table page */
  107. UWORD *tabmem;                    /* pointer to memory for the key labels */
  108. UWORD tablopage;                /* lowest key number on table page */
  109. UWORD tabhipage;                /* highest key number on table page */
  110. UWORD tablochar;                /* lowest key number in font */
  111. UWORD tabhichar;                /* highest key number in font */
  112. UBYTE tabpages;                    /* number of pages of the table */
  113. UBYTE tabpage;                    /* actual page number (0..tabpages-1) */
  114. UBYTE current;                    /* current highlighted key */
  115.  
  116. /* miscellaneous definitions */
  117. #define TAB_TOGGLE_        0        /* for CtrlTable_() */
  118. #define TAB_CLOSE_        1
  119. #define TAB_OPEN_        2
  120. #define TAB_NEWPAGE_    3
  121. #define TAB_NEWFONT_    4
  122.  
  123. #define SFON_INIT_        0        /* for SelectFont_() */
  124. #define SFON_FILL_        1
  125. #define SFON_SELECT_    2
  126.  
  127. #define GID_FONTSEL_    0        /* for struct NewGadget */
  128. #define GID_FONT_        1
  129. #define GID_CHAR_        2
  130. #define GID_DECIMAL_    3
  131. #define GID_STROKE_        4
  132. #define GID_PAGE_        5
  133. #define GID_HIDE_        6
  134. #define GID_QUIT_        7
  135. #define GID_ASCII_        8
  136.  
  137. #define MOUSE_SET_        0        /* for CtrlPointer_() */
  138. #define MOUSE_CLR_        1
  139. #define MOUSE_INIT_        2
  140. #define MOUSE_REMOVE_    3
  141.  
  142. struct
  143. {    BYTE line;                 /* line diff to previous gadget, last is -1 */
  144.     UBYTE textnum;             /* number of localized text string */
  145.     BYTE kind;                 /* parameter for CreateGadget (and ng_Flags),
  146.                                 actually BUTTON_KIND and TEXT_KIND,
  147.                                 negative: PLACETEXT_ABOVE */
  148.     UBYTE length;             /* for TEXT_KIND: number of chars */
  149.     UWORD width;             /* 0, later gets width in pixels */
  150.     UWORD fullwidth;         /* 0, later gets full width in pixels */
  151.     struct Gadget *gad;         /* NULL, later gets result of CreateGadget */
  152. } gads[]=
  153. {    {    0, MSG_FONTSEL, BUTTON_KIND,    0    },
  154.     {    1, 0,            TEXT_KIND,        31    },
  155.     {    1, MSG_CHAR,    TEXT_KIND,        1    },
  156.     {    1, MSG_DECIMAL, TEXT_KIND,        3    },
  157.     {    2, MSG_STROKE,    TEXT_KIND,        31    },
  158.     {    3, MSG_PAGE,    SLIDER_KIND,    15    },
  159.     {    1, MSG_HIDE,    BUTTON_KIND,    0    },
  160.     {    1, MSG_QUIT,    BUTTON_KIND,    0    },
  161.     {  -1                                    }
  162. };
  163.  
  164.  
  165. /*==== get catalog string localized if locale.library is open ====*/
  166. TEXT *GetCatalogStrQ_(UBYTE num)
  167. {    if (LocaleBase) return GetCatalogStr(cat, num, AppStrings[num].as_Str);
  168.     return AppStrings[num].as_Str;
  169. }
  170.  
  171. /*==== get character for "keyable" gagdets ====*/
  172. WORD GetGadgetChar_(const ULONG num)
  173. {    TEXT *s= strchr(GetCatalogStrQ_(num), '_');
  174.     return s? ToUpper(s[1]) : -1;
  175. }
  176.  
  177. /*==== clean up all before exit ====*/
  178. void CleanUp_(void)
  179. {    void CtrlTable_(UBYTE action);
  180.     void CtrlPointer_(UBYTE action);
  181.  
  182.     CtrlTable_(TAB_CLOSE_);
  183.     CtrlPointer_(MOUSE_REMOVE_);
  184.     if (pubscr) UnlockPubScreen(NULL, pubscr);
  185.     if (tabfont) CloseFont(tabfont);
  186.     if (freq) FreeAslRequest((APTR)freq);
  187.     if (broker) DeleteCxObjAll(broker);
  188.     if (brokport)
  189.     {    struct Message *msg;
  190.         while (msg= GetMsg(brokport)) ReplyMsg(msg);
  191.         DeleteMsgPort(brokport);
  192.     }
  193.     ArgArrayDone();
  194.     if (LocaleBase)
  195.     {    CloseCatalog(cat);
  196.         CloseLocale(locale);
  197.         CloseLibrary(LocaleBase);
  198.     }
  199.     if (AslBase) CloseLibrary(AslBase);
  200.     if (CxBase) CloseLibrary(CxBase);
  201.     if (DiskfontBase) CloseLibrary(DiskfontBase);
  202.     if (GadToolsBase) CloseLibrary(GadToolsBase);
  203.     if (GfxBase) CloseLibrary(GfxBase);
  204.     if (IconBase) CloseLibrary(IconBase);
  205.     if (IntuitionBase) CloseLibrary(IntuitionBase);
  206.     if (KeymapBase) CloseLibrary(KeymapBase);
  207.     if (UtilityBase) CloseLibrary(UtilityBase);
  208. }
  209.  
  210. /*==== bring error text to the user ====*/
  211. void ExitError_(TEXT *format, ...)
  212. {    void CtrlPointer_(UBYTE action);
  213.  
  214.     static struct EasyStruct easystruct=
  215.     {    sizeof(struct EasyStruct), 0, PRGNAME, NULL, NULL
  216.     };
  217.     ULONG idcmpflags;
  218.     va_list ap;
  219.  
  220.     if (IntuitionBase)
  221.     {    DisplayBeep(pubscr);
  222.         va_start(ap, format);
  223.         CtrlPointer_(MOUSE_SET_);
  224.         easystruct.es_TextFormat= format;
  225.         easystruct.es_GadgetFormat= GetCatalogStrQ_(MSG_ABORT_GAD);
  226.         EasyRequestArgs(win, &easystruct, NULL, &va_arg(ap, TEXT *));
  227.         CtrlPointer_(MOUSE_CLR_);
  228.     }
  229.  
  230.     exit(RETURN_FAIL);
  231. }
  232.  
  233. void ExitMemError_(void)
  234. {    ExitError_(GetCatalogStrQ_(MSG_NOMEMORY));
  235. }
  236.  
  237. /*==== set or clear busy pointer ====*/
  238. void CtrlPointer_(UBYTE action)
  239. {    static ULONG idcmpflags;
  240.  
  241.     /*>> busy mouse pointer image <<*/
  242.     static UWORD *pimage;            /* mouse imagedata in chip mem */
  243.     static UWORD mouseimage[]=        /* a 'simple sprite' */
  244.     {    0, 0,
  245.         0x0400, 0x07c0, 0x0000, 0x07c0, 0x0100, 0x0380, 0x0000, 0x07e0,
  246.         0x07c0, 0x1ff8, 0x1ff0, 0x3fec, 0x3ff8, 0x7fde, 0x3ff8, 0x7fbe,
  247.         0x7ffc, 0xff7f, 0x7efc, 0xffff, 0x7ffc, 0xffff, 0x3ff8, 0x7ffe,
  248.         0x3ff8, 0x7ffe, 0x1ff0, 0x3ffc, 0x07c0, 0x1ff8, 0x0000, 0x07e0,
  249.         0, 0
  250.     };
  251.  
  252.     switch (action)
  253.     {    case MOUSE_INIT_:
  254.             if (!(pimage= AllocMem(sizeof(mouseimage), MEMF_CHIP)))
  255.                 ExitMemError_();
  256.             CopyMem(mouseimage, pimage, sizeof(mouseimage));
  257.             break;
  258.         case MOUSE_SET_:
  259.             if (pimage && win)
  260.             {    idcmpflags= win->IDCMPFlags;
  261.                 ModifyIDCMP(win, IDCMP_MENUPICK);
  262.                 SetPointer(win, pimage, 16, 16, -6, 0);
  263.             }
  264.             break;
  265.         case MOUSE_CLR_:
  266.             if (pimage && win)
  267.             {    ClearPointer(win);
  268.                 if (idcmpflags) ModifyIDCMP(win, idcmpflags);
  269.             }
  270.             break;
  271.         case MOUSE_REMOVE_:
  272.             if (pimage) FreeMem(pimage, sizeof(mouseimage));
  273.             break;
  274.     }
  275. }
  276.  
  277. /*==== open library ====*/
  278. struct Library *OpenLibraryQ_(TEXT *str)
  279. {    struct Library *base;
  280.  
  281.     if (!(base= OpenLibrary(str, 0)))
  282.         ExitError_(GetCatalogStrQ_(MSG_NOTFOUND), str);
  283.     return base;
  284. }
  285.  
  286. /*==== allocate memory ====*/
  287. void *MAllocQ_(ULONG size)
  288. {    void *ptr;
  289.  
  290.     if (!(ptr= (void *)malloc(size))) ExitMemError_();
  291.     return ptr;
  292. }
  293.  
  294. /*==== fill in text display gadgets ====*/
  295. /*>>> necessary because GadTools don't center
  296.       the text or print more than one line!
  297.       NOTE: string has to end with '\n'!      <<<*/
  298. void SetGadgetDisplay_(struct Gadget *gad, TEXT *str)
  299. {    UWORD x= gad->LeftEdge, y= gad->TopEdge, height= gad->Height;
  300.     UBYTE lines= 0;
  301.     TEXT *s, *index;
  302.  
  303.     SetFont(win->RPort, win->WScreen->RastPort.Font);
  304.     SetDrMd(win->RPort, JAM1);
  305.     SetAPen(win->RPort, 0);
  306.     RectFill(win->RPort, x+2, y+1, x+gad->Width-4, y+height-2);
  307.  
  308.     s= str; while (s= strchr(s, '\n'))
  309.     {    s++;
  310.         lines++;
  311.     }
  312.     y+= ((height+1-lines*(win->RPort->Font->tf_YSize+1))>>1)
  313.         +win->RPort->Font->tf_Baseline;
  314.     SetDrMd(win->RPort, JAM2);
  315.     SetAPen(win->RPort, 1);
  316.     s= str; while (*s)
  317.     {    index= strchr(s, '\n');
  318.         Move(win->RPort,
  319.             x+((gad->Width-TextLength(win->RPort, s, index-s))>>1), y);
  320.         Text(win->RPort, s, index-s);
  321.         s= index+1;
  322.         y+= win->RPort->Font->tf_YSize+1;
  323.     }
  324. }
  325.  
  326. /*==== handle fonts ====*/
  327. void SelectFont_(UBYTE action)
  328. {    struct RastPort *rport;
  329.  
  330.     if (action == SFON_INIT_)
  331.     {    rport= &pubscr->RastPort;
  332.         goto setfont;
  333.     } else if (action == SFON_SELECT_)
  334.     {    CtrlPointer_(MOUSE_SET_);
  335.         if (AslRequestTags(freq,
  336.             ASLFO_TitleText, GetCatalogStrQ_(MSG_CHOOSEFONT),
  337.             ASLFO_Window, win,
  338.             ASLFO_InitialName, tabtattr.ta_Name,
  339.             ASLFO_InitialSize, tabtattr.ta_YSize,
  340.             TAG_DONE))
  341.         {    CloseFont(tabfont);
  342.             rport= win->RPort;
  343.             rport->Font= tabfont= OpenDiskFont(&freq->fo_Attr);
  344.  
  345. setfont:    tabtattr.ta_Name=  rport->Font->tf_Message.mn_Node.ln_Name;
  346.             tabtattr.ta_YSize= rport->Font->tf_YSize;
  347.             tabtattr.ta_Style= rport->Font->tf_Style;
  348.             tabtattr.ta_Flags= rport->Font->tf_Flags;
  349.             if (!tabfont) tabfont= OpenDiskFont(&tabtattr);
  350.  
  351.             if (tabtattr.ta_Flags&FPF_PROPORTIONAL) /* find biggest xsize */
  352.             {    UBYTE x= tabfont->tf_LoChar, n;
  353.                 tabxsize= 0;
  354.                 do
  355.                 {    n= TextLength(rport, &x, 1);
  356.                     if (n > tabxsize) tabxsize= n;
  357.                 } while (x++ != tabfont->tf_HiChar);
  358.             } else
  359.                 tabxsize= tabfont->tf_XSize;
  360.         }
  361.         CtrlPointer_(MOUSE_CLR_);
  362.     } else /* if (action == SFON_FILL_) */
  363.     {    TEXT s[31]= { ' ' };
  364.         strcpy(s, tabtattr.ta_Name);
  365.         sprintf(strrchr(s, '.'), "/%lu\n", tabtattr.ta_YSize);
  366.         SetGadgetDisplay_(gads[GID_FONT_].gad, s);
  367.     }
  368. }
  369.  
  370. /*==== put description of keystroke for character into buffer ====*/
  371. /*>>> actually function is guaranteed only for AmigaOS 2.04/2.1! <<<*/
  372. void MapANSIChar_(UBYTE chr, TEXT buffer[256])
  373. {    /* >> these definitions are hopefully ok in all national keymaps! << */
  374.     #define NUMDEADKEYS 5                /* a maximum of 16 is possible */
  375.     static TEXT deadkeys[NUMDEADKEYS]=    /* rawkey codes of deadkeys */
  376.     {    0x23, 0x24, 0x25, 0x26, 0x27
  377.     };
  378.  
  379.     struct KeyMap *km= AskKeyMapDefault(); /* pointer to default keymap */
  380.     UBYTE qualflags;                    /* qualifiers SHIFT, ALT, CTRL */
  381.     UBYTE key;                            /* raw key number 0x00 .. 0x7f */
  382.     UBYTE dead= 0;                        /* number of deadkey from table */
  383.  
  384.     const static BYTE mapoffsets[8][8]= /* [LoKeyMapTypes[lokey]][qualflags] */
  385.     {    /*  none,  S  ,   A ,  SA ,    C,  S C,   AC,  SAC */
  386.         {    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff    },    /* none */
  387.         {    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff    },    /* S    */
  388.         {    0x00, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff    },    /*  A   */
  389.         {    0x00, 0x01, 0x02, 0x03, 0xff, 0xff, 0xff, 0xff    },    /* SA   */
  390.         {    0x00, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff    },    /*   C  */
  391.         {    0x00, 0x01, 0xff, 0xff, 0x02, 0x03, 0xff, 0xff    },    /* S C  */
  392.         {    0x00, 0xff, 0x01, 0xff, 0x02, 0xff, 0x03, 0xff    },    /*  AC  */
  393.         {    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07    }    /* SAC  */
  394.     };
  395.  
  396.     buffer[0]= '\0';
  397.  
  398.     /*- get control characters using the common way -*/
  399.     if ((chr&0x7f) < ' ')
  400.     {    union
  401.         {    UWORD word;
  402.             struct
  403.             {    UBYTE code, qual;
  404.             } bytes;
  405.         } buf;
  406.  
  407.         if (MapANSI(&chr, 1, &buf, 1, NULL) > 0)
  408.         {    key= buf.bytes.code;
  409.             qualflags= 0;
  410.             if (buf.bytes.qual&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  411.                 qualflags|= KCF_SHIFT;
  412.             if (buf.bytes.qual&(IEQUALIFIER_LALT|IEQUALIFIER_RALT))
  413.                 qualflags|= KCF_ALT;
  414.             if (buf.bytes.qual&(IEQUALIFIER_CONTROL))
  415.                 qualflags|= KCF_CONTROL;
  416.             goto found;
  417.         }
  418.     }
  419.  
  420.     /*- find rawkey qualifier and code in keymap -*/
  421.     {    BYTE offset;                /* byte offset into LoKeyMap[lokey] */
  422.         BOOL deadflag;                /* FALSE: search non-dead, TRUE: dead */
  423.         UBYTE *kmtypes;                /* pointer into km_??KeyMapTypes */
  424.         ULONG *kmmap;                /* pointer into km_??KeyMap */
  425.  
  426.         for (deadflag= FALSE; deadflag <= TRUE; deadflag++)
  427.         {    for (qualflags= KC_NOQUAL; qualflags <= KC_VANILLA; qualflags++)
  428.             {    for (key= 0; key <= 0x78; key++)
  429.                 {    if (!(key&0x3f))
  430.                     {    kmtypes= key&0x40?
  431.                             km->km_HiKeyMapTypes : km->km_LoKeyMapTypes;
  432.                         kmmap= key&0x40? km->km_HiKeyMap: km->km_LoKeyMap;
  433.                     }
  434.                     offset= mapoffsets[*kmtypes&KC_VANILLA][qualflags];
  435.                     if (!(*kmtypes&KCF_NOP) && (offset >= 0))
  436.                     {    if (*kmtypes&KCF_DEAD)
  437.                         {    UBYTE *addr= (UBYTE *)*kmmap;
  438.                             if (addr[offset<<1]&DPF_MOD)
  439.                             {    addr+= addr[(offset<<1)|1]+deadflag;
  440.                                 dead= deadflag;
  441.                                 do
  442.                                 {    if (*addr == chr) goto found;
  443.                                     addr++;
  444.                                     dead++;
  445.                                 } while (deadflag && (dead != NUMDEADKEYS+1));
  446.                                 dead= 0;
  447.                             } else if (((UWORD *)addr)[offset] == (UWORD)chr)
  448.                                 goto found;
  449.                         } else if (!deadflag && !(offset&4))
  450.                         {    offset= (offset&3)^3;
  451.                             if (*kmtypes&KCF_STRING)
  452.                             {    UBYTE *addr= (UBYTE *)*kmmap;
  453.                                 if ((addr[offset<<1] == 1)
  454.                                     && (addr[addr[(offset<<1)|1]] == chr))
  455.                                     goto found;
  456.                             } else if (((UBYTE *)kmmap)[offset] == chr)
  457.                                 goto found;
  458.                         }
  459.                     }
  460.                     kmtypes++;
  461.                     kmmap++;
  462.                 }
  463.             }
  464.         }
  465.     }
  466.     return; /* not found */
  467.  
  468. found:
  469.     /*- put description into buffer -*/
  470.     {    struct InputEvent ie;            /* structure for MapRawKey() */
  471.         TEXT *index;                    /* temporary index for highkeys */
  472.  
  473.         static UBYTE highkeycodes[]=
  474.         {    0x40,            0x48,            0x50,    0x58,
  475.             0x41,            0x49,            0x51,    0x59,
  476.             0x42,                            0x52,    0x5f,
  477.             0x43,            0x4b,            0x53,
  478.             0x44,            0x4c,            0x54,    0x6e,
  479.             0x45,            0x4d,            0x55,    0x6f,
  480.             0x46,            0x4e,            0x56,    0x70,
  481.             0x47,            0x4f,            0x57,    0x71,        0
  482.         };
  483.         static TEXT *highkeytexts[]=
  484.         {    "space",        "page_up",        "f1",    "f9",
  485.             "backspace",    "page_down",    "f2",    "f10",
  486.             "tab",                            "f3",    "help",
  487.             "enter",        "f11",            "f4",
  488.             "return",        "up",            "f5",    "pause",
  489.             "esc",            "down",            "f6",    "f12",
  490.             "del",            "right",        "f7",    "home",
  491.             "insert",        "left",            "f8",    "end"
  492.         };
  493.         static TEXT numkeycodes[]=
  494.         {    0x0f, 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, 0x3c,
  495.             0x3d, 0x3e, 0x3f, 0x4a, 0x5a, 0x5b, 0x5c, 0x5d,
  496.             0x5e,                                           0
  497.         };
  498.  
  499.         ie.ie_Class= IECLASS_RAWKEY;
  500.         ie.ie_Qualifier= 0;
  501.         ie.ie_EventAddress= 0;
  502.  
  503.         if (dead)
  504.         {    strcpy(buffer, "alt  ,\n");
  505.             ie.ie_Code= deadkeys[dead-1];
  506.             MapRawKey(&ie, buffer+4, 1, km);
  507.         }
  508.  
  509.         if (qualflags&KCF_CONTROL)    strcat(buffer, "ctrl ");
  510.         if (qualflags&KCF_SHIFT)    strcat(buffer, "shift ");
  511.         if (qualflags&KCF_ALT)        strcat(buffer, "alt ");
  512.  
  513.         if (key && (index= strchr(highkeycodes, key)))
  514.         {    strcat(buffer, highkeytexts[index-highkeycodes]);
  515.             strcat(buffer, "\n");
  516.         } else
  517.         {    if (key && strchr(numkeycodes, key)) strcat(buffer, "numericpad ");
  518.             strcat(buffer, " \n");
  519.             ie.ie_Code= key;
  520.             MapRawKey(&ie, strrchr(buffer, ' '), 1, km);
  521.         }
  522.     }
  523. }
  524.  
  525. /*==== color gadget of current key ====*/
  526. void ColorCurrentKey_(UBYTE which, UBYTE color)
  527. {    UWORD x, y;
  528.  
  529.     SetFont(win->RPort, tabfont);
  530.     SetDrMd(win->RPort, JAM1);
  531.     SetAPen(win->RPort, color);
  532.     x= INTERWIDTH+((which-tablopage)%tabnumx)*(tabxsize+INTERWIDTH);
  533.     y= INTERHEIGHT+1+((which-tablopage)/tabnumx)*(tabtattr.ta_YSize+6);
  534.     RectFill(win->RPort, x+2, y,
  535.         x+2+tabxsize+INTERWIDTH-5, y+tabtattr.ta_YSize+6-3);
  536.     SetAPen(win->RPort, 1);
  537.     Move(win->RPort,
  538.         x+((1+INTERWIDTH+tabxsize-TextLength(win->RPort, &which, 1))>>1),
  539.         y+3-1+tabfont->tf_Baseline);
  540.     Text(win->RPort, &which, 1);
  541. }
  542.  
  543. /*==== show info of selected character ====*/
  544. void OutputCharInfo_(UBYTE num)
  545. {    TEXT s[256];
  546.  
  547.     if ((current >= tablopage) && (current < tabhipage))
  548.         /* de-color old actual key gadget */
  549.         ColorCurrentKey_(current, 0);
  550.  
  551.     if ((num >= tablopage) && (num < tabhipage))
  552.     {    /* set character gadget */
  553.         if ((num&0x7f) >= 0x20)
  554.         {    s[0]= num; s[1]= '\n'; s[2]= '\0';
  555.         } else
  556.             s[0]= '\0';
  557.         SetGadgetDisplay_(gads[GID_CHAR_].gad, s);
  558.         /* set decimal value gadget */
  559.         sprintf(s, "%lu\n", num);
  560.         SetGadgetDisplay_(gads[GID_DECIMAL_].gad, s);
  561.         /* set stroke gadget */
  562.         MapANSIChar_(num, s);
  563.         SetGadgetDisplay_(gads[GID_STROKE_].gad, s);
  564.  
  565.         /* color new actual key gadget */
  566.         ColorCurrentKey_(current= num, 3);
  567.     } else
  568.     {    SetGadgetDisplay_(gads[GID_CHAR_].gad, "\n");
  569.         SetGadgetDisplay_(gads[GID_DECIMAL_].gad, "\n");
  570.         SetGadgetDisplay_(gads[GID_STROKE_].gad, "\n");
  571.     }
  572. }
  573.  
  574. /*==== open or close character table ====*/
  575. void CtrlTable_(UBYTE action)
  576. {    static struct NewWindow newwin=
  577.     {    0, 0, 0, 0, 0, 1,
  578.         SLIDERIDCMP|BUTTONIDCMP|IDCMP_CLOSEWINDOW
  579.             |IDCMP_VANILLAKEY|IDCMP_RAWKEY,
  580.         WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_ACTIVATE
  581.             |WFLG_SMART_REFRESH|WFLG_NOCAREREFRESH|WFLG_GIMMEZEROZERO,
  582.         NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, PUBLICSCREEN
  583.     };
  584.  
  585.     static struct TagItem texttags[]=
  586.     {    GTTX_Border, TRUE
  587.     }, moretags[]=
  588.     {    STRINGA_ExitHelp, TRUE,
  589.         GT_Underscore, (ULONG)'_',
  590.         TAG_DONE
  591.     }, pagetags[]=
  592.     {    GA_RelVerify, TRUE,
  593.         PGA_Freedom, LORIENT_HORIZ,
  594.         TAG_DONE
  595.     };
  596.  
  597.     static BOOL tableopen;                /* TRUE if window is open */
  598.     BYTE i;                                /* loop variable */
  599.     UWORD m, n;                            /* temporary text lengths */
  600.     TEXT *str;                            /* temporary string pointer */
  601.     struct NewGadget newgad;            /* structure for CreateGadget() */
  602.     struct Gadget *keygad= NULL;        /* pointer to first key gadget */
  603.     static UWORD fieldwidth;            /* width of choice gadgets */
  604.     static UWORD fieldheight;            /* height of choice gadgets */
  605.     static xsize, ysize;                /* font size */
  606.     static UWORD winwidth, winheight;    /* window dimensions */
  607.  
  608.     if (action == TAB_TOGGLE_) action= TAB_OPEN_-tableopen;
  609.  
  610.     /*- bring window to front if FontViewQ loaded again -*/
  611.     if ((action == TAB_OPEN_) && tableopen)
  612.     {    WindowToFront(win);
  613.         return;
  614.     }
  615.  
  616.     /*- close window -*/
  617.     if (action == TAB_CLOSE_)
  618.     {    if (win)
  619.         {    TEXT *s= win->Title;
  620.             CloseWindow(win); win= NULL;
  621.             free(s);
  622.         }
  623.         if (tabmem)
  624.         {    free(tabmem); tabmem= NULL;
  625.         }
  626.         if (congad)
  627.         {    FreeGadgets(congad); congad= NULL; 
  628.         }
  629.         if (vi)
  630.         {    FreeVisualInfo(vi); vi= NULL;
  631.         }
  632.         tableopen= FALSE;
  633.         return;
  634.     }
  635.  
  636.     /*- get choice gadgets' dimensions or remove gadgets from window -*/
  637.     if (!tableopen)
  638.     {    UWORD u;                        /* temporary underscore width */
  639.  
  640.         /* lock default public screen and get visual information */
  641.         pubscr= LockPubScreen(NULL);
  642.         if (!tabfont) SelectFont_(SFON_INIT_);
  643.         rp= &pubscr->RastPort;
  644.         if (!(vi= GetVisualInfo(pubscr, TAG_DONE)))
  645. exitnowin:    ExitError_(GetCatalogStrQ_(MSG_NOWINDOW));
  646.  
  647.         /* find biggest xsize of font, set xsize and ysize */
  648.         if (rp->Font->tf_Flags&FPF_PROPORTIONAL)
  649.         {    UBYTE n, x= rp->Font->tf_LoChar;
  650.             if (32 > x) x= 32;
  651.             x--;
  652.             xsize= 0;
  653.             do
  654.             {    x++;
  655.                 n= TextLength(rp, &x, 1);
  656.                 if (n > xsize) xsize= n;
  657.             } while ((x < 126) && (x != rp->Font->tf_HiChar));
  658.             xsize= (xsize<<1)/3;
  659.         } else
  660.             xsize= rp->Font->tf_XSize;
  661.         ysize= rp->Font->tf_YSize;
  662.  
  663.         /* handle all widths correctly */
  664.         u= TextLength(rp, "_", 1);
  665.         fieldwidth= 0;
  666.         fieldheight= 2*INTERHEIGHT+6+ysize;
  667.         i= -1; while (gads[++i].line != -1)
  668.         {    fieldheight+= gads[i].line*(INTERHEIGHT+6+ysize);
  669.             str= gads[i].textnum? GetCatalogStrQ_(gads[i].textnum) : "";
  670.             m= TextLength(rp, str, strlen(str));
  671.             switch (gads[i].kind)
  672.             {    case SLIDER_KIND:
  673.                     n= xsize*gads[i].length;
  674.                     m+= INTERWIDTH+n;
  675.                     break;
  676.  
  677.                 case TEXT_KIND:
  678.                     n= xsize*(gads[i].length+1)+3*INTERWIDTH;
  679.                     if (i == GID_STROKE_)
  680.                     {    if (n > m) m= n;
  681.                     } else
  682.                     {    if (m) m+= INTERWIDTH;
  683.                         m+= n;
  684.                     }
  685.                     break;
  686.  
  687.                 case BUTTON_KIND:
  688.                     m= n= 3*INTERWIDTH+m;
  689.                     if (strchr(str, '_')) n-= u;
  690.             }
  691.             gads[i].width= n;
  692.             gads[i].fullwidth= m;
  693.             if (m > fieldwidth) fieldwidth= m;
  694.         }
  695.     } else
  696.     {    CtrlPointer_(MOUSE_SET_);
  697.         if (action == TAB_NEWFONT_)
  698.         {    RemoveGList(win, congad, -1);
  699.             FreeGadgets(congad); congad= NULL;
  700.             SetDrMd(win->RPort, JAM1);
  701.             SetAPen(win->RPort, 0);
  702.             RectFill(win->RPort, 0, 0, win->GZZWidth-1, win->GZZHeight-1);
  703.         } else /* if (action == TAB_NEWPAGE_) */
  704.         {    RemoveGList(win, gads[GID_QUIT_].gad->NextGadget, -1);
  705.             FreeGadgets(gads[GID_QUIT_].gad->NextGadget);
  706.             gads[GID_QUIT_].gad->NextGadget= NULL;
  707.             SetDrMd(win->RPort, JAM1);
  708.             SetAPen(win->RPort, 0);
  709.             RectFill(win->RPort, INTERWIDTH, 0,
  710.                 INTERWIDTH+tabnumx*(INTERWIDTH+tabxsize)-1, win->GZZHeight-1);
  711.         }
  712.     }
  713.  
  714.     /*- calculate new window dimensions -*/
  715.     winwidth= fieldwidth+3*INTERWIDTH;
  716.  
  717.     /*- calculate dimensions of table and create choice gadgets -*/
  718.     if (action != TAB_NEWPAGE_)
  719.     {    /* calculate dimensions of table */
  720.         {    UWORD scrheight;
  721.             if (action == TAB_OPEN_)
  722.             {    win= OpenWindowTags(NULL,
  723.                     WA_Width, 1,
  724.                     WA_Height, 1);
  725.             }
  726.             scrheight= win->WScreen->Height-win->BorderTop+win->BorderBottom
  727.                 -2*INTERHEIGHT;
  728.             if (action == TAB_OPEN_)
  729.             {    CloseWindow(win);
  730.                 win= NULL;
  731.             }
  732.             tabnumy= scrheight/(tabtattr.ta_YSize+INTERHEIGHT);
  733.         }
  734.         tabnumx= 1; m= ~0;
  735.         n= ((pubscr? pubscr : win->WScreen)->Width-winwidth-2*INTERWIDTH)
  736.             /(tabxsize+INTERWIDTH);
  737.         while (n > (tabnumx<<1)) { tabnumx<<= 1; m<<= 1; }
  738.         tablochar= tabfont->tf_LoChar&m;
  739.         tabhichar= (tabfont->tf_HiChar+tabnumx-1)&m;
  740.         m= tabnumx*tabnumy; n= tabhichar-tablochar;
  741.         tabpages= (m-n < 0)? (n+m-1)/m : 1;
  742.         n= (n+tabpages-1)/tabpages;
  743.         while ((((tabnumx*tabnumy)>>1) > n) && (tabnumx > 1)) tabnumx>>= 1;
  744.         tabnumy= ((tabhichar-tablochar+tabpages-1)
  745.             /tabpages+tabnumx-1)/tabnumx;
  746.         tablen= tabnumx*tabnumy;
  747.         if (tabmem) free(tabmem);
  748.         tabpage= 0;
  749.         tabmem= (UWORD *)MAllocQ_((tabhichar-tablochar)<<1);
  750.         if (!tabmem) ExitMemError_();
  751.         {    UWORD j;
  752.             for (j= tablochar; j != tabhichar; j++)
  753.                 tabmem[j-tablochar]= j<<8;
  754.         }
  755.         winwidth+= tabnumx*(INTERWIDTH+tabxsize);
  756.  
  757.         /* bring gadgets to screen */
  758.         CreateContext(&congad);
  759.         newgad.ng_TextAttr= (tableopen? win->WScreen : pubscr)->Font;
  760.         newgad.ng_VisualInfo= vi;
  761.         newgad.ng_TopEdge= INTERHEIGHT;
  762.         newgad.ng_GadgetID= 0;
  763.         i= -1; while ((n= gads[++i].line) != -1)
  764.         {    while (n-- > 0)
  765.                 newgad.ng_TopEdge+= ysize+6+INTERHEIGHT;
  766.             newgad.ng_Flags=
  767.                 (gads[i].kind == BUTTON_KIND)? PLACETEXT_IN :
  768.                 (i == GID_STROKE_)? PLACETEXT_ABOVE : PLACETEXT_LEFT;
  769.             newgad.ng_Height= (i == GID_PAGE_)? ysize : 6+ysize;
  770.             if (i == GID_STROKE_) newgad.ng_Height<<= 1;
  771.             newgad.ng_Width= gads[i].width;
  772.             newgad.ng_LeftEdge= winwidth-INTERWIDTH
  773.                     -((fieldwidth-gads[i].fullwidth)>>1)-gads[i].width;
  774.             newgad.ng_GadgetText= gads[i].textnum?
  775.  
  776.             GetCatalogStrQ_(gads[i].textnum) : NULL;
  777.                 gads[i].gad= CreateGadgetA((ULONG)gads[i].kind,
  778.                 i? gads[i-1].gad : congad, &newgad,
  779.                 (gads[i].kind == BUTTON_KIND)? moretags :
  780.                 (gads[i].kind == SLIDER_KIND)? pagetags : texttags);
  781.             newgad.ng_GadgetID++;
  782.         }
  783.         if (!gads[GID_QUIT_].gad) goto exitnowin;
  784.     }
  785.  
  786.     /*- create character set gadgets -*/
  787.     {    UWORD j;
  788.             newgad.ng_VisualInfo= vi;
  789.         newgad.ng_TextAttr= &tabtattr;
  790.         newgad.ng_Width= tabxsize+INTERWIDTH;
  791.         newgad.ng_Height= tabtattr.ta_YSize+6;
  792.         newgad.ng_TopEdge= INTERHEIGHT-newgad.ng_Height;
  793.         newgad.ng_GadgetID= GID_ASCII_+tabpage*tablen;
  794.  
  795.         tablopage= tablochar+tablen*tabpage;
  796.         tabhipage= tablochar+tablen*(tabpage+1);
  797.         if (tabhipage > tabhichar) tabhipage= tabhichar;
  798.  
  799.         {    struct Gadget *kgad= CreateContext(&keygad);
  800.             UWORD *tmptr= tabmem+tablopage-tablochar;
  801.  
  802.                 for (j= tablopage; j != tabhipage; j++)
  803.             {    if (!(j%tabnumx))
  804.                 {    newgad.ng_LeftEdge= INTERWIDTH;
  805.                     newgad.ng_TopEdge+= newgad.ng_Height;
  806.                 } else
  807.                     newgad.ng_LeftEdge+= newgad.ng_Width;
  808.                 newgad.ng_GadgetText= (TEXT *)tmptr++;
  809.                 kgad= CreateGadgetA(BUTTON_KIND, kgad, &newgad, NULL);
  810.                 newgad.ng_GadgetID++;
  811.             }
  812.  
  813.             if (!kgad) goto goexitnw;
  814.         }
  815.  
  816.         winheight= fieldheight;
  817.         if ((j= newgad.ng_TopEdge+newgad.ng_Height+INTERHEIGHT)
  818.             > winheight) winheight= j;
  819.     }
  820.  
  821.     /*- open or resize window -*/
  822.     if (!tableopen)
  823.     {    TEXT *l, *s, q[]= "%s: Hot Key = <%s>";
  824.         struct Catalog *ccat;
  825.  
  826.         if (LocaleBase)
  827.             ccat= OpenCatalogA(locale, "sys/commodities.catalog", NULL);
  828.         l= LocaleBase? GetCatalogStr(ccat, 1, q) : q;
  829.         s= MAllocQ_(PRGNAMELEN+1+strlen(l)+strlen(hotkey));
  830.         sprintf(s, l, PRGNAME, hotkey);
  831.         if (LocaleBase) CloseCatalog(ccat);
  832.  
  833.         if (!(win= OpenWindowTags(&newwin,
  834.             WA_Title, s,
  835.             WA_InnerWidth, winwidth,
  836.             WA_InnerHeight, winheight,
  837.             TAG_DONE)))
  838. goexitnw:
  839.         {    FreeGadgets(keygad);
  840.             goto exitnowin;
  841.         }
  842.  
  843.         winsig= 1<<win->UserPort->mp_SigBit;
  844.     } else if (action == TAB_NEWFONT_)
  845.     {    WORD y= win->WScreen->Height-win->TopEdge-winheight
  846.                 -win->BorderTop-win->BorderBottom;
  847.         WORD x= win->WScreen->Width-win->LeftEdge-winwidth
  848.                 -win->BorderLeft-win->BorderRight;
  849.         MoveWindow(win, (x > 0)? 0 : x, (y > 0)? 0 : y);
  850.         SizeWindow(win,
  851.             winwidth-(win->GZZWidth), winheight-(win->GZZHeight));
  852.     }
  853.  
  854.     /*- unlock public default screen -*/
  855.     if (pubscr)
  856.     {    UnlockPubScreen(NULL, pubscr); pubscr= NULL;
  857.     }
  858.  
  859.     /*- add gadget list to window -*/
  860.     if (action != TAB_NEWPAGE_) AddGList(win, congad, ~0, -1, NULL);
  861.     AddGList(win, keygad, ~0, -1, NULL);
  862.     RefreshGList(congad, win, NULL, -1);
  863.     GT_RefreshWindow(win, NULL);
  864.     GT_SetGadgetAttrs(gads[GID_PAGE_].gad, win, NULL,
  865.         GTSL_Max, tabpages-1,
  866.         TAG_DONE);
  867.  
  868.     tableopen= TRUE;
  869.     OutputCharInfo_(current);
  870.     SelectFont_(SFON_FILL_);
  871.     CtrlPointer_(MOUSE_CLR_);
  872. }
  873.  
  874. int main(int argc, TEXT *argv[])
  875. {    ULONG cxsig;                    /* signal flag of commodities' port */
  876.     ULONG sigrcvd;                    /* signal flags received from Wait() */
  877.     BOOL end= FALSE;                /* TRUE if program is to exit */
  878.     BYTE i;                            /* temporary variable */
  879.  
  880.     atexit(CleanUp_);
  881.  
  882.     /*- only allow AmigaOS >= 2.04 -*/
  883.     if (SysBase->lib_Version < 37)
  884.     {    BPTR file;
  885.         file= argc? Output() : Open("CON:0/0/350/30/" PRGNAME, MODE_NEWFILE);
  886.         Write(file, "Sorry, you'll need at least AmigaOS 2.04!\n", 42);
  887.         Delay(100);
  888.         Close(file);
  889.         return RETURN_FAIL;
  890.     }
  891.  
  892.     /*- open libraries -*/
  893.     IntuitionBase= OpenLibraryQ_("intuition.library");
  894.     if (LocaleBase= OpenLibrary("locale.library", 0))
  895.     {    locale= OpenLocale(NULL);
  896.         cat= OpenCatalogA(locale, PRGNAME ".catalog", NULL);
  897.     }
  898.     AslBase= OpenLibraryQ_("asl.library");
  899.     CxBase= OpenLibraryQ_("commodities.library");
  900.     DiskfontBase= OpenLibraryQ_("diskfont.library");
  901.     GadToolsBase= OpenLibraryQ_("gadtools.library");
  902.     GfxBase= OpenLibraryQ_("graphics.library");
  903.     IconBase= OpenLibraryQ_("icon.library");
  904.     KeymapBase= OpenLibraryQ_("keymap.library");
  905.     UtilityBase= OpenLibraryQ_("utility.library");
  906.  
  907.     /*- process arguments or tool types -*/
  908.     argv= ArgArrayInit(argc, argv);
  909.     newbroker.nb_Pri= (BYTE)ArgInt(argv, "CX_PRIORITY", 0);
  910.     i= !Stricmp(ArgString(argv, "CX_POPUP", "TRUE"), "TRUE");
  911.     hotkey= ArgString(argv, "CX_POPKEY", "ctrl alt f");
  912.  
  913.     /*- initialize as commodity with hotkey -*/
  914.     newbroker.nb_Descr= GetCatalogStrQ_(MSG_CXDESCR);
  915.     if (!(brokport= newbroker.nb_Port= CreateMsgPort())) ExitMemError_();
  916.     cxsig= 1<<brokport->mp_SigBit;
  917.     {    CxObj *filter;
  918.         LONG error;
  919.  
  920.         if (!(broker= CxBroker(&newbroker, &error)) || error
  921.             || !(filter= HotKey(hotkey, brokport, 0))
  922.             || (AttachCxObj(broker, filter), CxObjError(filter)))
  923.             if (error != CBERR_DUP)
  924.                 ExitError_(GetCatalogStrQ_(MSG_INITFAIL));
  925.             else
  926.                 return RETURN_OK;
  927.     }
  928.     ActivateCxObj(broker, TRUE);
  929.  
  930.     /*- allocate font requester structure -*/
  931.     if (!(freq= (struct FontRequest *)AllocAslRequestTags(ASL_FontRequest,
  932.         TAG_DONE))) ExitMemError_();
  933.  
  934.     /*- allocate chip mem for busy mouse pointer -*/
  935.     CtrlPointer_(MOUSE_INIT_);
  936.  
  937.     /*- eventually open window now -*/
  938.     current= 'Q';
  939.     if (i) CtrlTable_(TAB_OPEN_);
  940.  
  941.     /*- big message loop -*/
  942.     while (!end)
  943.     {    sigrcvd= Wait(SIGBREAKF_CTRL_C|cxsig|winsig);
  944.     
  945.         if (sigrcvd&SIGBREAKF_CTRL_C) end= TRUE;
  946.  
  947.         if (sigrcvd&winsig) /* table loop */
  948.         {    struct IntuiMessage *imsg;
  949.             BOOL pageflag= FALSE;
  950.  
  951.             while (pageflag || win)
  952.             {    BOOL closeflag= FALSE;
  953.                 BYTE i;
  954.  
  955.                 /* get new message from GadTools */
  956.                 imsg= GT_GetIMsg(win->UserPort);
  957.                 if (pageflag && (!imsg || ((imsg->Class != IDCMP_GADGETUP)
  958.                     || (imsg->Code != GID_PAGE_))))
  959.                 {    CtrlTable_(TAB_NEWPAGE_);
  960.                     pageflag= FALSE;
  961.                 }
  962.                 if (!imsg) break;
  963.  
  964.                 /* process Intuition message */
  965.                 switch (imsg->Class)
  966.                 {    case IDCMP_GADGETUP:
  967.                         i= ((struct Gadget *)imsg->IAddress)->GadgetID;
  968. select:                    switch (i)
  969.                         {    case GID_FONTSEL_:
  970.                                 SelectFont_(SFON_SELECT_);
  971.                                 CtrlTable_(TAB_NEWFONT_);
  972.                                 break;
  973.  
  974.                             case GID_HIDE_:
  975.                                 goto close;
  976.  
  977.                             case GID_QUIT_:
  978.                                 end= TRUE;
  979.                                 break;
  980.  
  981.                             case GID_PAGE_:
  982.                                 if (imsg->Code != tabpage)
  983.                                 {    tabpage= imsg->Code;
  984.                                     pageflag= TRUE;
  985.                                 }
  986.                                 break;
  987.  
  988.                             default:
  989.                                 OutputCharInfo_((UBYTE)i-GID_ASCII_+tablochar);
  990.                                 break;
  991.                         }
  992.                         break;
  993.  
  994.                     case IDCMP_VANILLAKEY:
  995.                     {    WORD c= ToUpper(imsg->Code);
  996.                         while (gads[++i].line != -1)
  997.                             if (c == GetGadgetChar_(gads[i].textnum))
  998.                                 goto select;
  999.                         c= imsg->Qualifier;
  1000.                         if ((c&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1001.                             && (c&IEQUALIFIER_NUMERICPAD))
  1002.                             switch (imsg->Code)
  1003.                             {    case '1':    goto raw_end; /* end */
  1004.                                 case '3':    goto raw_down; /* page down */
  1005.                                 case '7':    goto raw_home; /* home */
  1006.                                 case '9':    goto raw_up; /* page up */
  1007.                             }
  1008.                         break;
  1009.                     }
  1010.  
  1011.                     case IDCMP_RAWKEY:
  1012.                         switch (imsg->Code) /*>> from OS 2.1 and up! <<*/
  1013.                         {    case 0x48: /* page up */
  1014. raw_up:                            if (!tabpage) break;
  1015.                                 tabpage--;
  1016.                                 goto newpage;
  1017.                             case 0x49: /* page down */
  1018. raw_down:                        if (tabpage == tabpages-1) break;
  1019.                                 tabpage++;
  1020.                                 goto newpage;
  1021.                             case 0x70: /* home */
  1022. raw_home:                        if (!tabpage) break;
  1023.                                 tabpage= 0;
  1024.                                 goto newpage;
  1025.                             case 0x71: /* end */
  1026. raw_end:                        if (tabpage == tabpages-1) break;
  1027.                                 tabpage= tabpages-1;
  1028. newpage:                        GT_SetGadgetAttrs(gads[GID_PAGE_].gad,
  1029.                                     win, NULL,
  1030.                                     GTSL_Level, tabpage,
  1031.                                     TAG_DONE);
  1032.                         CtrlTable_(TAB_NEWPAGE_);
  1033.                                 break;
  1034.                         }
  1035.                         break;
  1036.  
  1037.                     case IDCMP_CLOSEWINDOW:
  1038. close:                    closeflag= TRUE;
  1039.                         break;
  1040.                 }
  1041.  
  1042.                 /* reply message and eventually close window */
  1043.                 GT_ReplyIMsg(imsg);
  1044.                 if (closeflag)
  1045.                 {    while (imsg= GT_GetIMsg(win->UserPort)) GT_ReplyIMsg(imsg);
  1046.                     CtrlTable_(TAB_CLOSE_);
  1047.                 }
  1048.             }
  1049.         }
  1050.  
  1051.         if (sigrcvd&cxsig) /* commodity loop */
  1052.         {    CxMsg *cxmsg;
  1053.  
  1054.             while (cxmsg= (CxMsg *)GetMsg(brokport))
  1055.             {    switch (CxMsgType(cxmsg))
  1056.                 {    case CXM_IEVENT:
  1057.                         CtrlTable_(TAB_TOGGLE_);
  1058.                         break;
  1059.                     case CXM_COMMAND:
  1060.                         switch (i= (BYTE)CxMsgID(cxmsg))
  1061.                         {    case CXCMD_DISABLE:
  1062.                             case CXCMD_ENABLE:
  1063.                                 ActivateCxObj(broker, i == CXCMD_ENABLE);
  1064.                                 break;
  1065.                             case CXCMD_KILL:
  1066.                                 end= TRUE;
  1067.                                 break;
  1068.                             case CXCMD_APPEAR:
  1069.                             case CXCMD_UNIQUE:
  1070.                             case CXCMD_DISAPPEAR:
  1071.                                 CtrlTable_((i == CXCMD_DISAPPEAR)?
  1072.                                     TAB_CLOSE_ : TAB_OPEN_);
  1073.                                 break;
  1074.                         }
  1075.                 }
  1076.                 ReplyMsg((struct Message *)cxmsg);
  1077.             }
  1078.         }
  1079.     }
  1080.  
  1081.     return RETURN_OK;
  1082. }
  1083.  
  1084. #ifdef _DCC
  1085. int wbmain(struct WBStartup *wbstart)
  1086. {    return main(0, (TEXT **)wbstart);
  1087. }
  1088. #endif
  1089.